// saveOGGSample.go
package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"gitee.com/wenxichang/sfont"
)

func main() {
	if len(os.Args) < 3 {
		fmt.Printf("用法: %s <soundfont文件> <样本名称>\n", filepath.Base(os.Args[0]))
		fmt.Printf("示例: %s MuseScore_General.sf3 \"Violin A4\"\n", filepath.Base(os.Args[0]))
		fmt.Printf("注意: 样本名称可以包含通配符 * 和 ?\n")
		os.Exit(1)
	}

	sfFile := os.Args[1]
	sampleNamePattern := os.Args[2]

	// 加载 SoundFont 文件
	sf := &sfont.SoundFont{}
	err := sf.Read(sfFile)
	if err != nil {
		log.Fatalf("读取 SoundFont 文件失败: %v", err)
	}

	// 查找匹配的样本
	matchedSamples := findMatchingSamples(sf, sampleNamePattern)
	if len(matchedSamples) == 0 {
		fmt.Printf("未找到匹配的样本: %s\n", sampleNamePattern)
		os.Exit(1)
	}

	fmt.Printf("找到 %d 个匹配的样本:\n", len(matchedSamples))
	for i, sample := range matchedSamples {
		fmt.Printf("  [%d] %s\n", i+1, sample.Name)
		printSampleInfo(sample)
	}

	// 保存每个匹配的样本
	successCount := 0
	for _, sample := range matchedSamples {
		err := saveOGGSample(sf, sample)
		if err != nil {
			log.Printf("保存样本 %s 失败: %v", sample.Name, err)
		} else {
			fmt.Printf("成功保存: %s.ogg\n", sanitizeFileName(sample.Name))
			successCount++
		}
	}

	fmt.Printf("\n完成! 成功保存 %d/%d 个样本\n", successCount, len(matchedSamples))
}

// findMatchingSamples 查找名称匹配的样本
func findMatchingSamples(sf *sfont.SoundFont, pattern string) []*sfont.Sample {
	var matched []*sfont.Sample

	for _, sample := range sf.Samples {
		if matchPattern(sample.Name, pattern) {
			matched = append(matched, sample)
		}
	}

	return matched
}

// matchPattern 简单的通配符匹配
func matchPattern(name, pattern string) bool {
	if pattern == "*" {
		return true
	}

	// 简单的通配符匹配实现
	if strings.Contains(pattern, "*") || strings.Contains(pattern, "?") {
		// 将通配符模式转换为简单的正则匹配
		pattern = strings.ReplaceAll(pattern, "*", ".*")
		pattern = strings.ReplaceAll(pattern, "?", ".")
		return matchSimpleRegex(name, pattern)
	}

	// 子字符串匹配（不区分大小写）
	return strings.Contains(strings.ToLower(name), strings.ToLower(pattern))
}

// matchSimpleRegex 简单的正则表达式匹配（仅支持 . 和 .*）
func matchSimpleRegex(name, pattern string) bool {
	if pattern == ".*" {
		return true
	}

	// 简单的实现：检查名称是否包含模式（去掉 .*）
	cleanPattern := strings.ReplaceAll(pattern, ".*", "")
	return strings.Contains(strings.ToLower(name), strings.ToLower(cleanPattern))
}

// saveOGGSample 将样本保存为 OGG 文件
func saveOGGSample(sf *sfont.SoundFont, sample *sfont.Sample) error {
	// 检查样本类型是否为 OGG 压缩
	if sample.SampleType&0x10 == 0 {
		return fmt.Errorf("样本不是 OGG 格式 (sampleType: 0x%04X)", sample.SampleType)
	}

	// 获取样本的原始数据
	rawData, err := extractOGGData(sf, sample)
	if err != nil {
		return fmt.Errorf("提取 OGG 数据失败: %v", err)
	}

	if len(rawData) == 0 {
		return fmt.Errorf("样本没有 OGG 数据")
	}

	// 创建 OGG 文件
	filename := sanitizeFileName(sample.Name) + ".ogg"
	file, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("创建文件失败: %v", err)
	}
	defer file.Close()

	// 写入 OGG 数据
	_, err = file.Write(rawData)
	if err != nil {
		return fmt.Errorf("写入 OGG 数据失败: %v", err)
	}

	return nil
}

// extractOGGData 从 SoundFont 中提取 OGG 数据
func extractOGGData(sf *sfont.SoundFont, sample *sfont.Sample) ([]byte, error) {
	// 对于 SF3 文件，样本数据已经是 OGG 格式
	// 我们需要从样本数据区域提取指定范围的数据

	if sf.SampleData == nil {
		return nil, fmt.Errorf("没有样本数据")
	}

	// 计算样本数据的字节范围
	startByte := sample.Start
	endByte := sample.End

	// 检查边界
	if startByte >= endByte {
		return nil, fmt.Errorf("样本起始位置大于等于结束位置")
	}

	if endByte > uint32(len(sf.SampleData)) {
		return nil, fmt.Errorf("样本数据超出范围: %d > %d", endByte, len(sf.SampleData))
	}

	// 提取 OGG 数据
	oggData := make([]byte, endByte-startByte)
	copy(oggData, sf.SampleData[startByte:endByte])

	return oggData, nil
}

// printSampleInfo 显示样本信息
func printSampleInfo(sample *sfont.Sample) {
	fmt.Printf("    起始位置: %d\n", sample.Start)
	fmt.Printf("    结束位置: %d\n", sample.End)
	fmt.Printf("    数据大小: %d 字节\n", sample.End-sample.Start)
	fmt.Printf("    采样率: %d Hz\n", sample.SampleRate)
	fmt.Printf("    原始音高: %d\n", sample.OrigPitch)
	fmt.Printf("    音高校正: %d\n", sample.PitchAdj)
	fmt.Printf("    样本类型: 0x%04X", sample.SampleType)

	// 解释样本类型
	if sample.SampleType&0x10 != 0 {
		fmt.Printf(" (OGG 压缩)")
	}
	if sample.SampleType&0x8000 != 0 {
		fmt.Printf(" (ROM 样本)")
	}
	fmt.Printf("\n")

	// 检查循环信息
	if sample.LoopStart != sample.LoopEnd {
		fmt.Printf("    循环: %d - %d\n", sample.LoopStart, sample.LoopEnd)
	} else {
		fmt.Printf("    循环: 无\n")
	}
}

// sanitizeFileName 清理文件名，移除非法字符
func sanitizeFileName(name string) string {
	// 移除或替换文件名中的非法字符
	invalidChars := []string{"/", "\\", ":", "*", "?", "\"", "<", ">", "|"}
	result := name
	for _, char := range invalidChars {
		result = strings.ReplaceAll(result, char, "_")
	}

	// 限制文件名长度
	if len(result) > 100 {
		result = result[:100]
	}

	return result
}

// 验证 OGG 文件头
func isValidOGG(data []byte) bool {
	if len(data) < 4 {
		return false
	}

	// OGG 文件以 "OggS" 开头
	return string(data[0:4]) == "OggS"
}
